package com.tonyodev.fetch2core.server;

import ohos.utils.Parcel;
import ohos.utils.Sequenceable;

import com.tonyodev.fetch2core.Extras;

import org.jetbrains.annotations.NotNull;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Objects;

/**
 * Request object sent to the Fetch File Server as JSON.
 *
 * @since 2021-05-20
 **/
public class FileRequest implements Sequenceable, Serializable {
    /**
     * 类型
     */
    public static final int TYPE_INVALID = -1;
    /**
     * 类型
     */
    public static final int TYPE_PING = 0;
    /**
     * 类型
     */
    public static final int TYPE_FILE = 1;
    /**
     * 类型
     */
    public static final int TYPE_CATALOG = 2;
    /**
     * 类型
     */
    public static final long CATALOG_ID = -1L;
    /**
     * CATALOG_NAME
     */
    public static final String CATALOG_NAME = "Catalog.json";
    /**
     * CATALOG_FILE
     */
    public static final String CATALOG_FILE = "/Catalog.json";
    /**
     * FIELD_TYPE
     */
    public static final String FIELD_TYPE = "Type";
    /**
     * FIELD_FILE_RESOURCE_ID
     */
    public static final String FIELD_FILE_RESOURCE_ID = "FileResourceId";
    /**
     * FIELD_RANGE_START
     */
    public static final String FIELD_RANGE_START = "Range-Start";
    /**
     * FIELD_RANGE_END
     */
    public static final String FIELD_RANGE_END = "Range-End";
    /**
     * FIELD_AUTHORIZATION
     */
    public static final String FIELD_AUTHORIZATION = "Authorization";
    /**
     * FIELD_CLIENT
     */
    public static final String FIELD_CLIENT = "Client";
    /**
     * FIELD_EXTRAS
     */
    public static final String FIELD_EXTRAS = "Extras";
    /**
     * FIELD_PAGE
     */
    public static final String FIELD_PAGE = "Page";
    /**
     * FIELD_SIZE
     */
    public static final String FIELD_SIZE = "Size";
    /**
     * FIELD_PERSIST_CONNECTION
     */
    public static final String FIELD_PERSIST_CONNECTION = "Persist-Connection";

    private int type;
    @NotNull
    private String fileResourceId;
    private long rangeStart;
    private long rangeEnd;
    @NotNull
    private String authorization;
    @NotNull
    private String client;
    @NotNull
    private Extras extras;
    private int page;
    private int size;
    private boolean persistConnection;

    /**
     * 构造函数
     */
    public FileRequest() {
        this.type = TYPE_INVALID;
        this.fileResourceId = String.valueOf(CATALOG_ID);
        this.rangeStart = 0L;
        this.rangeEnd = -1L;
        this.authorization = "";
        this.client = "";
        this.extras = Extras.getEmptyExtras();
        this.page = 0;
        this.size = 0;
        this.persistConnection = true;
    }

    /**
     * 构造函数
     *
     * @param type 类型
     * @param fileResourceId 文件id
     * @param rangeStart rangeStart
     * @param rangeEnd rangeEnd
     * @param authorization authorization
     * @param client client
     * @param extras extras
     * @param page 页
     * @param size 大小
     * @param persistConnection persistConnection
     */
    public FileRequest(int type, @NotNull String fileResourceId, long rangeStart, long rangeEnd, @NotNull String authorization, @NotNull String client, @NotNull Extras extras, int page, int size, boolean persistConnection) {
        this.type = type;
        this.fileResourceId = fileResourceId;
        this.rangeStart = rangeStart;
        this.rangeEnd = rangeEnd;
        this.authorization = authorization;
        this.client = client;
        this.extras = extras;
        this.page = page;
        this.size = size;
        this.persistConnection = persistConnection;
    }

    /**
     * 获取类型
     *
     * @return 类型
     */
    public int getType() {
        return type;
    }

    /**
     * 获取文件Id
     *
     * @return 文件Id
     */
    public String getFileResourceId() {
        return fileResourceId;
    }

    /**
     * 获取开始值
     *
     * @return 开始值
     */
    public long getRangeStart() {
        return rangeStart;
    }

    /**
     * 获取结束值
     *
     * @return 结束值
     */
    public long getRangeEnd() {
        return rangeEnd;
    }

    /**
     * 获取请求头
     *
     * @return 请求头
     */
    public String getAuthorization() {
        return authorization;
    }

    /**
     * 获取客户端
     *
     * @return 客户端
     */
    public String getClient() {
        return client;
    }

    /**
     * 获取附加值
     *
     * @return 附加值
     */
    public Extras getExtras() {
        return extras;
    }

    /**
     * 获取页
     *
     * @return 页
     */
    public int getPage() {
        return page;
    }

    /**
     * 获取大小
     *
     * @return 大小
     */
    public int getSize() {
        return size;
    }

    /**
     * 是否留存链接
     *
     * @return 是否留存
     */
    public boolean isPersistConnection() {
        return persistConnection;
    }

    /**
     * 获取json 格式数据
     *
     * @return string json
     */
    @NotNull
    public final String getToJsonString() {
        StringBuilder builder = (new StringBuilder()).append('{').append("\"Type\":").append(this.type).append(',').append("\"FileResourceId\":").append('"' + this.fileResourceId + '"').append(',').append("\"Range-Start\":").append(this.rangeStart).append(',').append("\"Range-End\":").append(this.rangeEnd).append(',').append("\"Authorization\":").append('"' + this.authorization + '"').append(',').append("\"Client\":").append('"' + this.client + '"').append(',').append("\"Extras\":").append(this.extras.toJSONString()).append(',').append("\"Page\":").append(this.page).append(',').append("\"Size\":").append(this.size).append(',').append("\"Persist-Connection\":").append(this.persistConnection).append('}');
        return builder.toString();
    }

    @Override
    public boolean marshalling(Parcel dest) {
        dest.writeSerializable(new HashMap(extras.getMap()));
        return dest.writeInt(type) && dest.writeString(fileResourceId) && dest.writeLong(rangeStart)
            && dest.writeLong(rangeEnd) && dest.writeString(authorization) && dest.writeString(client)
            && dest.writeInt(page) && dest.writeInt(size) && dest.writeInt(persistConnection ? 1 : 0);
    }

    /**
     * new FileRequest
     *
     * @return FileRequest
     */
    public FileRequest copy() {
        return new FileRequest(type, fileResourceId, rangeStart, rangeEnd, authorization, client, extras, page, size, persistConnection);
    }

    @Override
    public String toString() {
        return "FileRequest(type=" + this.type + ", fileResourceId=" + this.fileResourceId + ", rangeStart=" + this.rangeStart + ", rangeEnd=" + this.rangeEnd + ", authorization=" + this.authorization + ", client=" + this.client + ", extras=" + this.extras + ", page=" + this.page + ", size=" + this.size + ", persistConnection=" + this.persistConnection + ")";
    }

    /**
     * Sequenceable
     */
    public static final Sequenceable.Producer
        PRODUCER = new Sequenceable.Producer() {
        /**
         * new FileRequest
         * @param in Parcel
         * @return FileRequest
         */
        public FileRequest createFromParcel(Parcel in) {
            // Initialize an instance first, then do customized unmarshlling.
            FileRequest instance = new FileRequest();
            instance.unmarshalling(in);
            return instance;
        }
    };

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        FileRequest that = (FileRequest) o;
        return type == that.type
            && rangeStart == that.rangeStart
            && rangeEnd == that.rangeEnd
            && page == that.page
            && size == that.size
            && persistConnection == that.persistConnection
            && fileResourceId.equals(that.fileResourceId)
            && authorization.equals(that.authorization)
            && client.equals(that.client)
            && extras.equals(that.extras);
    }

    @Override
    public int hashCode() {
        return Objects.hash(type, fileResourceId, rangeStart, rangeEnd, authorization, client, extras, page, size, persistConnection);
    }

    @Override
    public boolean unmarshalling(Parcel parcel) {
        this.type = parcel.readInt();
        this.fileResourceId = parcel.readString();
        this.rangeStart = parcel.readLong();
        this.rangeEnd = parcel.readLong();
        this.authorization = parcel.readString();
        this.client = parcel.readString();
        this.page = parcel.readInt();
        this.size = parcel.readInt();
        this.persistConnection = parcel.readBoolean();
        this.extras = parcel.readSerializable(Extras.class);
        return true;
    }
}
